﻿using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics.CodeAnalysis;
using System.Windows;

namespace Testing.Helpers.Images
{
    /// <summary>
    /// Class for getting screenshots.
    /// </summary>
    public static class ScreenCapture
    {

        /// <summary>
        /// Creates window screenshot.
        /// </summary>
        /// <param name="hWnd">Window handle.</param>
        /// <returns>Window screenshot.</returns>
        public static Bitmap CaptureWindowScreenshot(IntPtr hWnd)
        {
            var rect = new NativeMethods.Rect();
            NativeMethods.GetWindowRect(hWnd, ref rect);
            return GetRectScreenshot(rect);
        }

        /// <summary>
        /// Creates Image from rectangle and saves it to file.
        /// </summary>
        /// <param name="handle">Window Handle.</param>
        /// <param name="filename">Image file path.</param>
        /// <param name="format">Image file format.</param>
        public static void CaptureWindowScreenshotToFile(IntPtr handle, string filename, ImageFormat format)
        {
            Image img = CaptureWindowScreenshot(handle);
            img.Save(filename, format);
        }


        /// <summary>
        /// Creates image from rectangle.
        /// </summary>
        /// <param name="handle">Window Handle. </param>
        /// <param name="rect">Bounding rectangle.</param>
        /// <returns>Image</returns>
        public static Image CaptureImage(IntPtr handle, Rect rect)
        {
            NativeMethods.Rect imageRect = ConvertRect(rect);
            NativeMethods.GetWindowRect(handle, ref imageRect);
            Bitmap bitmap = GetRectScreenshot(imageRect);
            return bitmap;
        }


        /// <summary>
        /// Creates Image from rectangle and saves it to file.
        /// </summary>
        /// <param name="handle">Window Handle.</param>
        /// <param name="rect">Bounding rectangle.</param>
        /// <param name="filename">Image file path.</param>
        /// <param name="format">Image file format.</param>
        public static void CaptureImageToFile(IntPtr handle, Rect rect, string filename, ImageFormat format)
        {
            Image img = rect == Rect.Empty ? new Bitmap(1, 1) : CaptureImage(handle, rect);
            img.Save(filename, format);
        }

        private static Bitmap GetRectScreenshot(NativeMethods.Rect rect)
        {
            int width = rect.right - rect.left;
            int height = rect.bottom - rect.top;

            var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            Graphics graphics = Graphics.FromImage(bmp);
            graphics.CopyFromScreen(rect.left, rect.top, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);

            return bmp;
        }

        private static NativeMethods.Rect ConvertRect(Rect rect)
        {
            return new NativeMethods.Rect
            {
                bottom = (int)rect.Bottom,
                left = (int)rect.Left,
                right = (int)rect.Right,
                top = (int)rect.Top
            };
        }

        /// <summary>
        /// Helper class containing User32 API functions.
        /// </summary>
        private static class NativeMethods
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct Rect
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }

            [SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", MessageId = "return")]
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
        }
    }
}

